Example from Section 21.5.4.1 (page 441) in K20P64M72SF1RM manual (MK20DX128 processor used on Teensy 3.1/3.2).
From the manual:
...the following TCD entry is configured to transfer 16 bytes of data. The eDMA is programmed for one iteration of the major loop transferring 16 bytes per iteration. The source memory has a byte wide memory port located at
0x1000
. The destination memory has a 32-bit port located at0x2000
. The address offsets are programmed in increments to match the transfer size: one byte for the source and four bytes for the destination. The final source and destination addresses are adjusted to return to their beginning values.TCDn_CITER = TCDn_BITER = 1 TCDn_NBYTES = 16 TCDn_SADDR = 0x1000 TCDn_SOFF = 1 TCDn_ATTR[SSIZE] = 0 TCDn_SLAST = -16 TCDn_DADDR = 0x2000 TCDn_DOFF = 4 TCDn_ATTR[DSIZE] = 2 TCDn_DLAST_SGA= –16 TCDn_CSR[INT_MAJ] = 1 TCDn_CSR[START] = 1 (Should be written last after all other fields have been initialized) All other TCDn fields = 0
This generates the following event sequence:
- User write to the
TCDn_CSR[START]
bit requests channel service.- The channel is selected by arbitration for servicing.
- eDMA engine writes:
TCDn_CSR[DONE] = 0
,TCDn_CSR[START] = 0
,TCDn_CSR[ACTIVE] = 1
.
In [1]:
import numpy as np
from teensy_minimal_rpc import SerialProxy
import teensy_minimal_rpc.DMA as dma
# Disconnect from existing proxy (if available)
try:
del proxy
except NameError:
pass
proxy = SerialProxy()
In [2]:
N = 512
proxy.free_all()
# Allocate source array
src_addr = proxy.mem_alloc(N)
# Allocate destination array
dst_addr = proxy.mem_alloc(N)
# Fill first 16 bytes of source array with the numbers 1-16
proxy.mem_cpy_host_to_device(src_addr, np.arange(1, 17, dtype='uint8'))
# Fill the destination array with all zeros
proxy.mem_fill_uint32(dst_addr, 0, N / 4)
In [3]:
# Create Transfer Control Descriptor configuration to match the settings
# shown in the example from the manual.
XFER_REQUEST = dma.TCD(
# TCDn_CITER = TCDn_BITER = 1
CITER_ELINKNO=dma.R_TCD_ITER_ELINKNO(ITER=1),
BITER_ELINKNO=dma.R_TCD_ITER_ELINKNO(ITER=1),
# TCDn_NBYTES = 16
NBYTES_MLNO=16,
# TCDn_SADDR = 0x1000
SADDR=int(src_addr),
# TCDn_SOFF = 1
SOFF=1,
# TCDn_ATTR[SSIZE] = 0
# See `TCDn_ATTR[DSIZE]` below.
# TCDn_SLAST = -16
SLAST=-16,
# TCDn_DADDR = 0x2000
DADDR=int(dst_addr),
# TCDn_DOFF = 4
DOFF=4,
# TCDn_ATTR[DSIZE] = 2
ATTR=dma.R_TCD_ATTR(SSIZE=dma.R_TCD_ATTR._8_BIT,
DSIZE=dma.R_TCD_ATTR._32_BIT),
# TCDn_DLAST_SGA= –16
DLASTSGA=-16,
# TCDn_CSR[INT_MAJ] = 1
# We won't use interrupts here...
# TCDn_CSR[START] = 1 (Should be written last after all other fields have been initialized)
CSR=dma.R_TCD_CSR(START=1)
# All other TCDn fields = 0
)
In [4]:
print 'SOURCE: ', proxy.mem_cpy_device_to_host(src_addr, 16)
# Fill the destination array with all zeros
proxy.mem_fill_uint32(dst_addr, 0, N / 4)
print 'TARGET:'
print ' Before:', proxy.mem_cpy_device_to_host(dst_addr, 16)
# Apply TCD configuration to DMA channel 0 to conduct transfer.
proxy.update_dma_TCD(0, XFER_REQUEST)
print ' After:', proxy.mem_cpy_device_to_host(dst_addr, 16)
In [5]:
# Read serialized TCD protocol buffer message for DMA channel 0 from device.
serialized_tcd0 = proxy.read_dma_TCD(0)
# Deserialize message into Python Protocol Buffer message.
tcd0 = dma.TCD.FromString(serialized_tcd0.tostring())
# Verify DMA operation is complete
# See TCD Control and Status section for more info (21.3.29/424 in manual).
assert(tcd0.CSR.DONE)